/**
 * Carnegie Mellon University
 * School of Computer Science
 * MSIT eBusiness Technology
 * 
 * Team 8 - Infinity (2011 Spring)
 * infinity-team8@googlegroups.com
 * 
 * Professor: Jeffrey L. Eppinger
 * Program Faculty: Sujata Telang
 */

package model;

import java.sql.Date;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Arrays;

import org.mybeans.dao.DAOException;
import org.mybeans.factory.BeanFactory;
import org.mybeans.factory.BeanFactoryException;
import org.mybeans.factory.BeanTable;
import org.mybeans.factory.DuplicateKeyException;
import org.mybeans.factory.MatchArg;
import org.mybeans.factory.RollbackException;
import org.mybeans.factory.Transaction;

import databean.CustomerBean;
import databean.TransactionBean;


public class CustomerDAO {
	private BeanFactory<CustomerBean> factory;
	
	public CustomerDAO() throws DAOException {
		try {
			// Get a BeanTable so we can create the "user" table
	        BeanTable<CustomerBean> customerTable = BeanTable.getInstance(CustomerBean.class,"customer");
	        
	        if (!customerTable.exists()) customerTable.create("customerID");
	        
	        // Long running web apps need to clean up idle database connections.
	        // So we can tell each BeanTable to clean them up.  (You would only notice
	        // a problem after leaving your web app running for several hours.)
	        customerTable.setIdleConnectionCleanup(true);
	
	        // Get a BeanFactory which the actions will use to read and write rows of the "user" table
	        factory = customerTable.getFactory();
	        
	        
	        //create pre-defined user 1
	        if (lookup(1) == null)
	        {
		        //insert three users as a default when creating the user table
		        try {
	
		        	Transaction.begin();

		        	CustomerBean dbCustomer = factory.create();
		        	dbCustomer.setUserName("Obama");
		        	dbCustomer.setPassword("Obama");
		        	dbCustomer.setFirstName("Barack");
		        	dbCustomer.setLastName("Obama");
		        	dbCustomer.setAddressLine1("1600 Pennsylvania Avenue");
		        	dbCustomer.setCity("Washington D.C.");
		        	dbCustomer.setState("DC");
		        	dbCustomer.setZip("20006");
		        	dbCustomer.setCash(3000000);
		        	Transaction.commit();
	
				} catch (DuplicateKeyException e) {
					throw new DAOException("Username 'Obama' already exists");
				} catch (RollbackException e) {
					throw new DAOException(e);
				} finally {
					if (Transaction.isActive()) Transaction.rollback();
				}
	        }
	        
	        
	        //create pre-defined user 2
	        if (lookup(2) == null)
	        {
		        //insert three users as a default when creating the user table
		        try {
	
		        	Transaction.begin();
		        	factory = customerTable.getFactory();
		        	
		        	CustomerBean dbCustomer = factory.create();
		        	dbCustomer.setUserName("Amber");
		        	dbCustomer.setPassword("Amber");
		        	dbCustomer.setFirstName("Amber");
		        	dbCustomer.setLastName("Vivis");
		        	dbCustomer.setAddressLine1("417 North Craig Street");
		        	dbCustomer.setCity("Pittsburgh");
		        	dbCustomer.setState("PA");
		        	dbCustomer.setZip("15213");
		        	dbCustomer.setCash(2000000);
		        	Transaction.commit();
	
				} catch (DuplicateKeyException e) {
					throw new DAOException("Username 'Amber' already exists");
				} catch (RollbackException e) {
					throw new DAOException(e);
				} finally {
					if (Transaction.isActive()) Transaction.rollback();
				}
	        }
	        
	        
	        //create pre-defined user 3
	        if (lookup(3) == null)
	        {
		        //insert three users as a default when creating the user table
		        try {
	
		        	Transaction.begin();
		        	factory = customerTable.getFactory();
		        	
		        	CustomerBean dbCustomer = factory.create();
		        	dbCustomer.setUserName("Jeff");
		        	dbCustomer.setPassword("Jeff");
		        	dbCustomer.setFirstName("Jeff");
		        	dbCustomer.setLastName("Eppinger");
		        	dbCustomer.setAddressLine1("Gates Hillman Complex");
		        	dbCustomer.setAddressLine2("4800 Forbes Ave");
		        	dbCustomer.setCity("Pittsburgh");
		        	dbCustomer.setState("PA");
		        	dbCustomer.setZip("15213");
		        	dbCustomer.setCash(1000000);
		        	Transaction.commit();
	
				} catch (DuplicateKeyException e) {
					throw new DAOException("Username 'Jeff' already exists");
				} catch (RollbackException e) {
					throw new DAOException(e);
				} finally {
					if (Transaction.isActive()) Transaction.rollback();
				}
	        }
	        
	        
		} catch (BeanFactoryException e) {
			throw new DAOException(e);
		}
	}
	
	public void create(CustomerBean customer) throws DAOException {
        try {

        	if (lookup(customer.getUserName())==null) {
        			        	
	        	Transaction.begin();
	        	
	        	CustomerBean dbCustomer = factory.create();
				factory.copyInto(customer,dbCustomer);
				
				Transaction.commit();
	        	
        	} else {
        		
        		throw new DuplicateKeyException("A user named "+customer.getUserName()+" already exists");
        		
        	}
			
		} catch (DuplicateKeyException e) {
			throw new DAOException("A user named "+customer.getUserName()+" already exists");
		} catch (RollbackException e) {
			throw new DAOException(e);
		} finally {
			if (Transaction.isActive()) Transaction.rollback();
		}
	}
	
	
	/**
	 * look up by customer id
	 * @param customerID
	 * @return
	 * @throws DAOException
	 */
	public CustomerBean lookup(long customerID) throws DAOException {
		try {
			return factory.lookup(customerID);
		} catch (RollbackException e) {
			throw new DAOException(e);
		}
	}
	
	/**
	 * look up by username
	 * @param userName
	 * @return
	 * @throws DAOException
	 */
	public CustomerBean lookup(String userName) throws DAOException {
		try {
			
			if (factory.match(MatchArg.equals("userName", userName)) == null ||
            		factory.match(MatchArg.equals("userName", userName)).length == 0) {
				return null;
			} else {
				return factory.match(MatchArg.equals("userName", userName))[0];
			}
			
		} catch (RollbackException e) {
			throw new DAOException(e);
		}
	}
	
	/**
	 * deposit by customer id and amount
	 * @param customerID
	 * @return
	 * @throws DAOException
	 */
	public CustomerBean deposit(long customerID, long amount) throws DAOException {
		try {
			
			Transaction.begin();
			
			CustomerBean customer = factory.lookup(customerID);
			customer.setCash(customer.getCash()+amount);
			
			Transaction.commit();
			
			return customer;
			
		} catch (RollbackException e) {
			throw new DAOException(e);
		} finally {
			if (Transaction.isActive()) Transaction.rollback();
		}
	}
	
	
	/**
	 * set last trading day by customer id
	 * @param customerID
	 * @return
	 * @throws DAOException
	 */
	public void setLastTradingDay(long customerID, Date date) throws DAOException {
		try {
			
			Transaction.begin();
			
			CustomerBean customer = factory.lookup(customerID);
			customer.setLastTradingDay(date);
			
			Transaction.commit();
						
		} catch (RollbackException e) {
			throw new DAOException(e);
		} finally {
			if (Transaction.isActive()) Transaction.rollback();
		}
	}
	
	/**
	 * get last trading day by customer id
	 * @param customerID
	 * @return
	 * @throws DAOException
	 */
	public Date getLastTradingDay(long customerID) throws DAOException {
		try {
			
			Transaction.begin();			
			CustomerBean customer = factory.lookup(customerID);
			Transaction.commit();
			
			return customer.getLastTradingDay();
			
						
		} catch (RollbackException e) {
			throw new DAOException(e);
		} finally {
			if (Transaction.isActive()) Transaction.rollback();
		}
	}
	
	
	
	/**
	 * request by customer id and amount
	 * @param customerID
	 * @return
	 * @throws DAOException
	 */
	public CustomerBean request(long customerID, long amount) throws DAOException {
		try {
			
			Transaction.begin();
			
			CustomerBean customer = factory.lookup(customerID);
			customer.setCash(customer.getCash()-amount);
			
			Transaction.commit();
			
			return customer;
			
		} catch (RollbackException e) {
			throw new DAOException(e);
		} finally {
			if (Transaction.isActive()) Transaction.rollback();
		}
	}
	
	/**
	 * look up available cash by username
	 * @param userName
	 * @return
	 * @throws DAOException
	 */
	public long getAvailableCash(String userName) throws DAOException {
		CustomerBean customer = lookup(userName);
		long availableCash = customer.getCash();
		
		TransactionDAO transactionDAO = new TransactionDAO();
		TransactionBean[] transactions = transactionDAO.getPendingTransactions();
		
		for (int i = 0; i<transactions.length; i++) {
			if (transactions[i].getCustomerID() == customer.getCustomerID()) {
								
				if (transactions[i].getTransactionType().equals("request")) {
					availableCash = availableCash - transactions[i].getAmount();
				}
				
				if (transactions[i].getTransactionType().equals("deposit")) {
					availableCash = availableCash + transactions[i].getAmount();
				}
				
				if (transactions[i].getTransactionType().equals("buy")) {
					availableCash = availableCash - transactions[i].getAmount();
				}
				
			}
		}
		
		return availableCash;
	}
	
	
	/**
	 * look up available cash by username
	 * @param userName
	 * @return
	 * @throws DAOException
	 */
	public String getAvailableCashFormatted(String userName) throws DAOException {
		long cash = getAvailableCash(userName);
		
		NumberFormat formatter = new DecimalFormat("##0.00");
		String s = formatter.format(((double)cash/100));
		
		return s;
	}
	
	/**
	 * get formatted cash
	 * @param userName
	 * @return
	 * @throws DAOException
	 */
	public String getCashFormatted(String userName) throws DAOException {
		CustomerBean customer = lookup(userName);
		long cash = customer.getCash();
		
		NumberFormat formatter = new DecimalFormat("##0.00");
		String s = formatter.format(((double)cash/100));
		
		return s;
	}
	
	
	protected BeanFactory<CustomerBean> getFactory() { return factory; }
	
	public CustomerBean[] getCustomers() throws DAOException {
		try {
			CustomerBean[] customers = factory.match();
			Arrays.sort(customers);
			return customers;
		} catch (RollbackException e) {
			throw new DAOException(e);
		}
	}
	
	public void setPassword(String userName, String password) throws DAOException {
        try {
        	Transaction.begin();
			CustomerBean dbCustomer = lookup(userName);
			
			if (dbCustomer == null) {
				throw new DAOException("User "+userName+" no longer exists");
			}
			
			dbCustomer.setPassword(password);
			Transaction.commit();
		} catch (RollbackException e) {
			throw new DAOException(e);
		} finally {
			if (Transaction.isActive()) Transaction.rollback();
		}
	}
	
}
